#!/bin/bash -e

function info() {
echo Usage: `basename $0` '[-h -o] name'
exit 1
}

while getopts  ":p:f:h:i" opt; do
	case  $opt  in
		p) out_prefix=$OPTARG;;
		f) suffix=$OPTARG;;
        h) host=$OPTARG;;
        o) port=$OPTARG;;
		*) info;;
	esac
done
shift $(($OPTIND - 1))


if [ $# -lt 1 ]; then info; fi

virtual=~/virtual/web

. $virtual/bin/activate

echo virtual path $virtual
which python
python -c '
import sys;                  
for path in sys.path:
    print path
'


dir=`pwd`
name=$1
bpts=blueprints
test=views
model=models
blueprint=bpt
blueprint_file=bpt_test
base=base
form=forms


pip show $name && pip uninstall -y $name 
test -d $name && rm -r $name

mkdir -p $name/$name/static/$bpts
mkdir -p $name/$name/templates/$bpts && cd $name

cat << setup > setup.py
from setuptools import setup

setup(
    name='$name',
    packages=['$name'],
    include_package_data=True,
    install_requires=[
        'flask', 'flask-login', 'flask-openid',
        'flask-mail', 'flask-wtf', 'flask-babel',
        'flask-whooshalchemy', 'flask-sqlalchemy',
        'coverage', 'flipflop', 'sqlalchemy-migrate',
        'guess-language'
        
    ],
)
setup

cat <<requirements > requirements.txt
flask
flask-login
flask-openid
flask-mail
flask-sqlalchemy
sqlalchemy-migrate
flask-whooshalchemy
flask-wtf
flask-babel
flup
guess_language
flipflop
coverage
requirements

cat << run > run.py && chmod 755 run.py
#!/usr/bin/env/ python
from $name import app
app.run(debug=True)
run

key=$name
config=config
cat << config > $config.py 
import os
basedir = os.path.abspath(os.path.dirname(__file__))

SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, '$name.db')
SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')

WTF_CSRF_ENABLED = True # more secure.
SECRET_KEY = '$key' # create a cryptographic token that is used to validate a form

OPENID_PROVIDERS = [
    {'name': 'Google', 'url': 'https://www.google.com/accounts/o8/id'},
    {'name': 'Yahoo', 'url': 'https://me.yahoo.com'},
    {'name': 'AOL', 'url': 'http://openid.aol.com/<username>'},
    {'name': 'Flickr', 'url': 'http://www.flickr.com/<username>'},
    {'name': 'MyOpenID', 'url': 'https://www.myopenid.com'}]
    
config

cat << create_db > create_db.py && chmod 755 create_db.py 
#!/usr/bin/env python
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO # ?.
from $name.$model import db
import os.path
db.create_all()
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
    api.create(SQLALCHEMY_MIGRATE_REPO, 'database repository')
    api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
else:
    api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, api.version(SQLALCHEMY_MIGRATE_REPO))
create_db



cat << db_migrate > db_migrate.py && chmod 755 db_migrate.py
#!/usr/bin/env python 
from __future__ import frint
import imp
from migrate.versioning import api
from $name import db
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
migration = SQLALCHEMY_MIGRATE_REPO + ('/versions/%03d_migration.py' % (v+1))
tmp_module = imp.new_module('old_model')
old_model = api.create_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
exec(old_model, tmp_module.__dict__)
script = api.make_update_script_for_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, tmp_module.meta, db.metadata)
open(migration, "wt").write(script)
api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
print('New migration saved as ' + migration)
print('Current database version: ' + str(v))
db_migrate

cat << db_upgrade > db_upgrade.py && chmod 755 db_upgrade.py
#!/usr/bin/env python 
from __future__ import frint
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
print('Current database version: ' + str(v))
db_upgrade


cat << db_downgrade > db_downgrade.py && chmod 755 db_downgrade.py
#!/usr/bin/env python 
from __future__ import frint
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
api.downgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO, v - 1)
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
print('Current database version: ' + str(v))
db_downgrade

cd $name



cat << init > __init__.py
from flask import Flask
import os
from flask_login import LoginManager
from flask_openid import OpenID
from config import basedir
# app = Flask(__name__)
# app.config.from_object('$config')

def create_app(config_filename=None):
    app = Flask(__name__)
    # app.config.from_pyfile(config_filename)
    app.config.from_object('$config')
    
    oid = OpenID(app, os.path.join(basedir, 'tmp')) # ?

    from $name.$model import db
    db.init_app(app)
    
    lm = LoginManager()
    lm.init_app(app)

    # from $name.$bpt.x import xx
    # app.register_blueprint(xx)

    return app, db, lm, oid
    

    
from $name import $test, $model
# Putting the import at the end avoids the circular import error.
init


cat << name > $test.py
from flask import render_template, flash, redirect, session, url_for, request, g
from $name import create_app
from .forms import LoginForm
from $name.$blueprint_file import $blueprint
from .$model import User, Post

app, db, lm, oid  = create_app()

@lm.user_loader
def load_user(id):
    return User.query.get(int(id))

@app.route('/')
@app.route('/index')
def index():
    user = {'nickname': 'Miguel'}  # fake user
    posts = [  # fake array of posts
        { 
            'author': {'nickname': 'John'}, 
            'body': 'Beautiful day in Portland!' 
        },
        { 
            'author': {'nickname': 'Susan'}, 
            'body': 'The Avengers movie was so cool!' 
        }
    ]
    return render_template("index.html",
                           title='Home',
                           user=user,
                           posts=posts)

@app.route('/login', methods=['GET', 'POST'])
@oid.loginhandler
def login():
    if g.user is not None and g.user.is_authenticated:
        return redirect(url_for('index')) # better than redirect('/index')
        
    form = LoginForm()
    if form.validate_on_submit():
        flash('Login requested for OpenID="%s", remember_me=%s' %
              (form.openid.data, str(form.remember_me.data)))
              
        session['remember_me'] = form.remember_me.data
        return oid.try_login(form.openid.data, ask_for=['nickname', 'email'])
        # return redirect('/index')
    return render_template('login.html', 
                           title='Sign In',
                           form=form,
                           providers=app.config['OPENID_PROVIDERS'])
    
app.register_blueprint($blueprint)
# app.register_blueprint($blueprint, url_prefix='/pages')

name


cat << form > $form.py
from flask_wtf import Form
from wtforms import StringField, BooleanField
from wtforms.validators import DataRequired 
#The DataRequired validator simply checks that the field is not submitted empty

class LoginForm(Form):
    openid = StringField('openid', validators=[DataRequired()])
    remember_me = BooleanField('remember_me', default=False)
form

cat << model > $model.py
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    nickname = db.Column(db.String(64), index=True, unique=True)
    email = db.Column(db.String(120), index=True, unique=True)
    posts = db.relationship('Post', backref='author', lazy='dynamic')
    # posts, that is constructed as a db.relationship field. This is not an actual database field, so it isn't in our database diagram
    
    @property
    def is_authenticated(self):
        return True

    @property
    def is_active(self):
        return True

    @property
    def is_anonymous(self):
        return False

    def get_id(self):
        try:
            return unicode(self.id)  # python 2
        except NameError:
            return str(self.id)  # python 3
            
    def __repr__(self):
        return '<User %r>' % (self.nickname)

class Post(db.Model):
    id = db.Column(db.Integer, primary_key = True)
    body = db.Column(db.String(140))
    timestamp = db.Column(db.DateTime)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id')) # user or User?

    def __repr__(self):
        return '<Post %r>' % (self.body)
         
model


cat << blueprint > $blueprint_file.py
from flask import Blueprint, render_template, abort, current_app
from jinja2 import TemplateNotFound

$blueprint = Blueprint('$bpts', __name__,
                        template_folder='templates')

@$blueprint.route('/')
def index():
    return render_template(current_app.config['INDEX_TEMPLATE'])
    
@$blueprint.route('/bpt', defaults={'page': 'index'})
@$blueprint.route('/bpt/<page>')
def show(page):
    try:
        return render_template('%s.html' % page)
    except TemplateNotFound:
        abort(404)
blueprint

:>static/style.css
cat << index >templates/index.html
{# could from render_template's args#}
{% extends "$base.html" %}
{% block content %}
    <h1>Hi, {{ user.nickname }}!</h1>
    {% for post in posts %}
    <div><p>{{ post.author.nickname }} says: <b>{{ post.body }}</b></p></div>
    {% endfor %}
{% endblock %}
index

cat << base >templates/$base.html
<!-- 
One interesting property of flash messages is that once they are requested through the get_flashed_messages function they are removed from the message list
-->
<html>
  <head>
    {% if title %}
    <title>{{ title }} - microblog</title>
    {% else %}
    <title>microblog</title>
    {% endif %}
  </head>
  <body>
    <div>Microblog: <a href="/index">Home</a></div>
    <hr>
    {% with messages = get_flashed_messages() %}
      {% if messages %}
        <ul>
        {% for message in messages %}
            <li>{{ message }} </li>
        {% endfor %}
        </ul>
      {% endif %}
    {% endwith %}
    {% block content %}{% endblock %}
  </body>
</html>
base

cat << login >templates/login.html
<!-- extend from base layout -->
<!-- The form.hidden_tag() template argument will get replaced with a hidden field that implements the CSRF prevention that we enabled in the configuration. -->
{% extends "$base.html" %}

{% block content %}
<script type="text/javascript">
function set_openid(openid, pr)
{
    u = openid.search('<username>')
    if (u != -1) {
        // openid requires username
        user = prompt('Enter your ' + pr + ' username:')
        openid = openid.substr(0, u) + user
    }
    form = document.forms['login'];
    form.elements['openid'].value = openid
}
</script>
<h1>Sign In</h1>
<form action="" method="post" name="login">
    {{ form.hidden_tag() }}
    <p>
        Please enter your OpenID, or select one of the providers below:<br>
        {{ form.openid(size=80) }}
        {% for error in form.openid.errors %}
          <span style="color: red;">[{{error}}]</span>
        {% endfor %}<br>
        |{% for pr in providers %}
          <a href="javascript:set_openid('{{ pr.url }}', '{{ pr.name }}');">{{ pr.name }}</a> |
        {% endfor %}
    </p>
    <p>{{ form.remember_me }} Remember Me</p>
    <p><input type="submit" value="Sign In"></p>
</form>
{% endblock %}
login

echo logout >templates/logout.html
echo 404 > templates/404.html
echo $bpts.index > templates/$bpts/index.html
echo body {background:pink} > static/$bpts/style.css

# echo test > test/test.html


cd $dir/$name
pip install -e .

./create_db.py # only need run once
./db_migrate.py
# ./db_upgrade.py


export FLASK_APP=$name # absolute path seems wrong
export FLASK_DEBUG=true

host=${host:=192.168.10.113}
port=${port:=5000}
flask run -h $host -p $port




